package column

import (
	"fmt"
	"game/game-db/orm/metag"
	"reflect"
	"strings"
	"unsafe"
)

type IStringColumnMeta interface {
	IColumnMeta
	Extra() string
	Length() int
}

type StringColumnMeta struct {
	ColumnMeta
	length int32
	extra  []string
}

// func (t *StringColumnMeta) Extra() []string {
// 	return t.extra
// }

// func (t *StringColumnMeta) Length() int32 {
// 	if t.length <= 0 {
// 		return 255
// 	} else {
// 		return t.length
// 	}
// }

func (t *StringColumnMeta) FillValue(objField reflect.Value, fieldValue reflect.Value) {
	if objField.CanSet() {
		objField.Set(fieldValue)
	} else {
		objField = reflect.NewAt(objField.Type(), unsafe.Pointer(objField.UnsafeAddr())).Elem()
		objField.Set(fieldValue)
	}
}
func (t *StringColumnMeta) TakeValue(objField reflect.Value) interface{} {
	if objField.CanInterface() {
		return objField.Interface()
	} else {
		objField = reflect.NewAt(objField.Type(), unsafe.Pointer(objField.UnsafeAddr())).Elem()
		return objField.Interface()
	}
}

func (t *StringColumnMeta) DbColumnType() string {
	if len(t.extra) == 1 {
		if t.extra[0] == "text" {
			return "text"
		} else if t.extra[0] == "mediumtext" {
			return "mediumtext"
		} else if t.extra[0] == "longtext" {
			panic("you want to save 4g string content to db, are you serious?")
		} else {
			panic("nothing is defined to the string field!")
		}
	} else {
		return fmt.Sprintf("varchar(%v)", t.length)
	}
}

func (t *StringColumnMeta) DefaultValue() string {
	if len(t.extra) == 1 {
		if t.extra[0] == "text" {
			return ""
		} else if t.extra[0] == "mediumtext" {
			return ""
		} else if t.extra[0] == "longtext" {
			panic("you want to save 4g string content to db, are you serious?")
		} else {
			panic("nothing is defined to the string field!")
		}
	} else {
		return "DEFAULT ''"
	}
}

func (t *StringColumnMeta) IsChange(dbColumnType string, dbColumnExtra string) bool {
	if len(t.extra) == 1 {
		if t.extra[0] == "text" && strings.HasPrefix(dbColumnType, "text") {
			return false
		} else if t.extra[0] == "mediumtext" && strings.HasPrefix(dbColumnType, "mediumtext") {
			return false
		} else {
			return true
		}
	} else {
		typeStr := fmt.Sprintf("varchar(%v)", t.length)
		if strings.Contains(dbColumnType, typeStr) {
			return false
		} else {
			return true
		}
	}
}

func NewStringField(structField reflect.StructField, columnMetag metag.ColumnMetag) IColumnMeta {
	var meta StringColumnMeta
	meta.fillBaseValue(structField, columnMetag)
	if columnMetag.Length <= 0 {
		meta.length = 255
	} else {
		meta.length = columnMetag.Length
	}
	if columnMetag.Extra != "" {
		meta.extra = strings.Split(columnMetag.Extra, ",")
	} else {
		meta.extra = []string{}
	}
	return &meta
}
